package com.tianyalei.zuul.demo.zuulserver.filter;


import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.tianyalei.zuul.demo.zuulserver.exception.NoPermissionException;

import com.tianyalei.zuul.demo.zuulserver.utils.JwtUtils;
import com.tianyalei.zuul.zuulauth.zuul.AuthChecker;
import com.tianyalei.zuul.zuulauth.zuul.AuthInfoHolder;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.tianyalei.zuul.zuulauth.zuul.AuthChecker.*;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;


/**
 *
 *@author wuweifeng wrote on 2019/8/12.
 * @author ratel modify on 2022/04/10
 */

@Component
public class PermissionFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private RouteLocator routeLocator;

    @Resource
    private AuthChecker authChecker;

    @Autowired
    JwtUtils jwtUtils;


    @Autowired
    private AuthInfoHolder authInfoHolder;


    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 2;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest serverHttpRequest = ctx.getRequest();

        String jwtToken = serverHttpRequest.getHeader("token");
        if (jwtToken == null) {
            //没有Authorization
            throw new NoPermissionException();
        }
        Claims claimByToken = jwtUtils.getClaimByToken(jwtToken);

        String  userId = claimByToken.getSubject();
        if(userId==null){
            throw new NoPermissionException();
        }

        String userType = "order-admin";
        Set<String> RoleIdSet = authInfoHolder.findByUser(userId);

        Set<String> permissionCodes = new HashSet<>();
        for (String userRole : RoleIdSet) {
            Set<String> byRole = authInfoHolder.findByRole(userRole);
            permissionCodes.addAll(byRole);
        }

        //类似于  /zuuldmp/core/test
        String requestPath = serverHttpRequest.getRequestURI();
        //获取请求的method
        String method = serverHttpRequest.getMethod().toUpperCase();
        //获取所有路由信息，找到该请求对应的appName
        List<Route> routeList = routeLocator.getRoutes();
        //Route{id='one', fullPath='/zuuldmp/auth/**', path='/**', location='auth', prefix='/zuuldmp/auth',
        String appName = null;
        String path = null;
        for (Route route : routeList) {
            if (requestPath.startsWith(route.getPrefix())) {
                //取到该请求对应的微服务名字
                appName = route.getId().replace("/","");
               // path = requestPath.replace(route.getPrefix(), route.getLocation());
                path = requestPath.replace(route.getPrefix(),"");
            }
        }
        if (appName == null) {
            throw new NoPermissionException(404, "不存在的服务");
        }


        //取到该用户的role、permission
        //访问  auth 服务的 GET  /project/my 接口
        int code = authChecker.check(
                serverHttpRequest,
                userType, //这里正常应该是userRoles。但是我的业务是根据USER_TYPE在代码里作为RequireRole的。按自己的实际填写
                permissionCodes);
        switch (code) {
            case CODE_NO_APP:
                throw new NoPermissionException(code, "不存在的服务");
            case CODE_404:
                throw new NoPermissionException(code, "无此接口或GET POST方法不对");
            case CODE_NO_ROLE:
                throw new NoPermissionException(code, "用户无该接口所需role");
            case CODE_NO_CODE:
                throw new NoPermissionException(code, "用户无该接口所需权限");
            case CODE_OK:
                ctx.addZuulRequestHeader("USER_ID", userId);
            default:
                break;
        }
        return null;
    }
}